深入理解 iOS 热修复原理 | 您所在的位置:网站首页 › ios aspects › 深入理解 iOS 热修复原理 |
原文链接 背景顾名思义热修复就是使 App 具备线上修复 bug 的能力,但是遗憾的是苹果出于安全的考虑禁用了热修复。虽然 App 审核加快了,但是依然无法很好的控制线上 bug 的影响范围。由于 JSPatch 存在审核风险,所以我们需要另辟蹊径,自研一套适合自己的热修复框架。 目标大部分线上 bug 并不需要完全替换原方法实现才能修复问题,我们可以在原来的方法实现前后增加一些自定的方法调用,或者是修改原方法的调用参数,或者是修改其内部的某一个方法调用即可修复问题。 - (void)sayHelloTo:(NSString *)name { // 当 name = nil 会发生 nil 异常。所以我们需要加一个 nil 保护逻辑 // 像这种情况就不需要完全替换原方法实现,只需要在该方法调用前增加一个 if 条件语句即可 //fix code // if (name == nil) { // return; // } [self.nameList addObject:name]; NSLog(@"Hello %@", name); }综上所述,热修复只需要具备以下几点即可: 方法替换为空实现 方法参数修改 方法返回值修改 方法调用前后插入自定义代码 支持任意 OC 方法调用 支持赋值语句 支持 if 语句:==、!=、>、>=、 Assemble)解决办法: 使用__bridge_transfer修饰符将返回对象的内存管理权移交出来,让外部对象管理其内存 // 方法1 id resultObj = nil; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; invocation.target = [NSObject class]; invocation.selector = @selector(new); [invocation invoke]; void *result; [invocation getReturnValue:&result]; if ([selName isEqualToString:@"alloc"] || [selName isEqualToString:@"new"] || [selName isEqualToString:@"copy"] || [selName isEqualToString:@"mutableCopy"]) { resultObj = (__bridge_transfer id)result; } else { resultObj = (__bridge id)result; } 采用常规方法调用代替 NSInvocation // 方法2 id resultObj = nil; if ([selName isEqualToString:@"alloc"]) { resultObj = [[target class] alloc]; } else if ([selName isEqualToString:@"new"]) { resultObj = [[target class] new]; } else if ([selName isEqualToString:@"copy"]) { resultObj = [target copy]; } else if ([selName isEqualToString:@"mutableCopy"]) { resultObj = [target mutableCopy]; } else { NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; invocation.target = [NSObject class]; invocation.selector = @selector(new); [invocation invoke]; void *result; [invocation getReturnValue:&result]; resultObj = (__bridge id)result; } 审核分析其实能不能成功上线是热修复的首要前提,我们辛辛苦苦开的框架如果上不了线,那一切都是徒劳无功。下面就来分析下其审核风险。 首先这个是我们自研的,所以苹果审核无法通过静态代码扫描识别。 其次系统库内部也大量使用了消息转发机制。可以通过符号断点验证_objc_msgForward和forwardInvocation:。所以不存在风险。 苹果无法采用动态检验消息转发,非系统调用都不能使用,这个成本太大了,几乎不可能。 Aspects 库目前线上有大量使用,为此不用担心。就算 Aspects 被禁用,参考 Aspects 自己实现也不难。综上所述:无审核风险。 当然热修复框架只是为了更好的控制线上 bug 影响范围和给用户更好的体验。不建议基于其它目的使用🤔 后记随着项目的业务复杂度增加,线上问题可能存在一些 C 函数的动态调用和 block 参数的修改,这边介绍一个强大的库,外部函数接口:libffi,它也可以拦截函数和获取函数调用参数。相比 Aspects,其功能更加强大,不但可以动态调用 C 函数,而且还可以用 libffi 实现一套基于 IMP 替换(拥有更好的性能)的热修复框架。有兴趣的童鞋请参考:libffi doc 和 如何动态调用 C 函数 取名深入只是为了引人注目,实则只是个人的一点心得。由于水平有限,如有不对之处,欢迎大家批评指正。 如果觉得文章不错的话,欢迎🌟以资鼓励😄 温馨提示: 阅读文章的时候建议搭配示例 HotFixDemo,这样理解会更加深刻。 参考文献 Objective-C Runtime Programming Guide NSInvocation returns value but makes app crash with EXC_BAD_ACCESS JSPatch 实现原理详解 objc_msgSend_stret objc_msgSend() Tour Part 1: The Road Map -rac_signalForSelector: may fail for struct returns Objective-C Automatic Reference Counting (ARC) Aspects |
CopyRight 2018-2019 实验室设备网 版权所有 |